検証RDS用のCloudFormationスタック削除時にスナップショットを残さない
みなさんこんにちは、杉金です。
検証用のRDSをCloudFormationで気軽に作ったり消したい時に意識しておくべきDeletionPolicy
について紹介します。
先に結論
CloudFormationではAWS::RDS::DBCluster
とAWS::RDS::DBInstance
のDeletionPolicy
はデフォルトでSnapshot
になっています。
CloudFormationスタック削除後にRDSのスナップショットが不要な場合やオプショングループも1つのCloudFormationテンプレートで合わせて作成/削除する場合はDeletionPolicy
をDelete
に設定すると良いです。
どういうこと?
実際の動きを一部紹介しながら解説します。まずはCloudFormationテンプレートを作成します。利用するリソースについての設定条件は次の通りですが、サンプル的なものですのでお好みで修正ください。
- サブネットグループ : スタック作成時のパラメータで指定
- セキュリティグループ : スタック作成時のパラメータで指定
- パラメーターグループ : CloudFormationテンプレートで合わせて作成
- オプショングループ : CloudFormationテンプレートで合わせて作成
条件をもとに以下のようなテンプレートを用意します。
AWSTemplateFormatVersion: '2010-09-09' Description: DB Stack Parameters: SubnetGroupName: Type: String Default: 'db-subnet-group' SecurityGroups: Type: String Default: 'sg-xxxxxxxxxxx' Resources: MyDB: Type: AWS::RDS::DBInstance Properties: DBInstanceIdentifier: test-mysql Engine: mysql EngineVersion: 8.0.26 MasterUsername: admin MasterUserPassword: '{{resolve:secretsmanager:xxxxxxx:SecretString:password}}' OptionGroupName: !Ref MyDBOptionGroup DBParameterGroupName: !Ref MyDBParameterGroup MultiAZ: false BackupRetentionPeriod: 0 DBSubnetGroupName: !Ref SubnetGroupName VPCSecurityGroups: - !Ref SecurityGroups AutoMinorVersionUpgrade: false PreferredMaintenanceWindow: sat:15:00-sat:15:30 DBInstanceClass: db.t3.medium StorageType: gp2 AllocatedStorage: '20' MyDBParameterGroup: Type: AWS::RDS::DBParameterGroup Properties: Family: MySQL8.0 Description: Database Parameter Group Parameters: character_set_client: utf8mb4 character_set_connection: utf8mb4 character_set_database: utf8mb4 character_set_results: utf8mb4 character_set_server: utf8mb4 time_zone: Asia/Tokyo MyDBOptionGroup: Type: AWS::RDS::OptionGroup Properties: EngineName: mysql MajorEngineVersion: '8.0' OptionGroupDescription: Database Option Group OptionConfigurations: - OptionName: MARIADB_AUDIT_PLUGIN
このテンプレートを使ってCloudFormationスタックを作成します。検証を終えたと想定してスタックを削除しようとすると次のエラーが起きます。
The option group 'XXXXXXX' cannot be deleted because it is in use.
オプショングループを削除しようとしたけど他のリソースが使っているよ、と言っていますね。 使っているリソースを特定してみましょう。RDSのコンソールから対象のオプショングループを選択します。
「関連付けられたDBインスタンスとスナップショット」を見るとスナップショットで使われていることが分かります。
AWS::RDS::DBInstance
でDeletionPolicy
を定義しない場合、デフォルトのSnapshot
になるため、削除時にRDSのスナップショットが作成されます。スナップショットを手動で削除して、再度CloudFormationスタックの削除を実行すると今後は削除に成功します。
オプショングループ作成のテンプレートを分けることでエラーは発生しませんが、スナップショットは残ります。
スナップショットが不要であれば、DeletionPolicy
をDelete
に設定することでスナップショットを残さず、オプショングループも合わせて削除できます。設定としてはテンプレートにDeletionPolicy
を一行加えるだけです。DeletionPolicy
を加えたテンプレートは以下です。
AWSTemplateFormatVersion: '2010-09-09' Description: DB Stack Parameters: SubnetGroupName: Type: String Default: 'db-subnet-group' SecurityGroups: Type: String Default: 'sg-xxxxxxxxxxx' Resources: MyDB: Type: AWS::RDS::DBInstance Properties: DBInstanceIdentifier: test-mysql Engine: mysql EngineVersion: 8.0.26 MasterUsername: admin MasterUserPassword: '{{resolve:secretsmanager:xxxxxxx:SecretString:password}}' OptionGroupName: !Ref MyDBOptionGroup DBParameterGroupName: !Ref MyDBParameterGroup MultiAZ: false BackupRetentionPeriod: 0 DBSubnetGroupName: !Ref SubnetGroupName VPCSecurityGroups: - !Ref SecurityGroups AutoMinorVersionUpgrade: false PreferredMaintenanceWindow: sat:15:00-sat:15:30 DBInstanceClass: db.t3.medium StorageType: gp2 AllocatedStorage: '20' DeletionPolicy: Delete MyDBParameterGroup: Type: AWS::RDS::DBParameterGroup Properties: Family: MySQL8.0 Description: Database Parameter Group Parameters: character_set_client: utf8mb4 character_set_connection: utf8mb4 character_set_database: utf8mb4 character_set_results: utf8mb4 character_set_server: utf8mb4 time_zone: Asia/Tokyo MyDBOptionGroup: Type: AWS::RDS::OptionGroup Properties: EngineName: mysql MajorEngineVersion: '8.0' OptionGroupDescription: Database Option Group OptionConfigurations: - OptionName: MARIADB_AUDIT_PLUGIN
このテンプレートであればスタック削除時にRDSのスナップショットを作成せずにRDSインスタンスとオプショングループ、パラメーターグループを削除します。1行加えるだけで、スタック削除後に手動でスナップショットを削除する手間が省けます。ちなみにパラメーターグループはスナップショットの情報に保持されないため、パラメーターグループ削除時にオプショングループのような使用中エラーは起きずに削除されます。
どこまで1つのテンプレートに定義するべきか
今回はサブネットグループやセキュリティグループは事前に作成したものを指定していましたので、このあたりのリソース作成もテンプレートに含めると依存関係の問題が発生しやすいです。オプショングループやパラメーターグループを複数のRDSで共有するケースもあります。どこまで1つのテンプレートに含めるべきかは悩ましくケースバイケースですが、CloudFormationのベストプラクティスにガイドラインが載っていますので参考になります。
Organize your stacks by lifecycle and ownership
DeletionPolicy
について
DeletionPolicy
を設定する多くのケースでは、CloudFormationスタック削除後も残しておきたいリソースを定義する際にDeletionPolicy
を使用します。DeletionPolicy
については以下のページに情報が記載されています。
Exception: The default policy is Snapshot for AWS::RDS::DBCluster resources and for AWS::RDS::DBInstance resources that don't specify the DBClusterIdentifier property.
RDSについて抜粋しましたがAWS::RDS::DBCluster
とAWS::RDS::DBInstance
のDeletionPolicy
はデフォルトでSnapshot
であるため今回のようなケースであればDelete
を定義します。Delete
に定義したテンプレートをそのまま本番用に流用するのは危険ですので、テンプレートをチェックする際にDeletionPolicy
で検索をかけてみて誤った定義をしていないかチェックすると良いでしょう。また、CloudFormationのテンプレート記法はJSONかYAMLどちらでも良いですが、YAMLであれば#でコメントを書けますので、補足的なコメントを加えるとなお良いです。
CloudFormationデザイナーでテンプレートを作成する際は#によるコメントは非推奨ですのでご注意ください。
AWS CloudFormation template formats
We recommend that you don't add # YAML comments to your templates in Designer. If your YAML template has # comments, Designer doesn't preserve those comments when converting the template to JSON. In addition, if you modify your template in Designer (for example, if you move a resource on the canvas), your comments are lost.
最後に
スタックの削除保護があるため普段からDeletionPolicy
を意識したことはそれほどありませんでした。今回のケースに遭遇して、オプショングループとスナップショットって紐付けられているんだということに気づきました。RDSのDeletionPolicy
のデフォルトがSnapshot
になっているのは転ばぬ先の杖っぽくて良い考えだと思います。手軽にリソースを作成、削除できるのがクラウドサービスの利点である一方で、誤って削除した時のこと(フールプルーフ)も意識しておくべきだなと改めて思いました。